﻿using System.Net;
using System.Xml.Linq;

namespace Bing
{

    /// <summary>
    /// The Bing Application Programming Interface (API), Version 2, enables developers to programmatically submit queries to and retrieve results from the Bing Engine. This topic introduces the online documentation and additional resources that support use of the Bing API.
    /// </summary>
    public static class API
    {
        /// <summary>
        /// Use the Ad <see cref="ApiHelper.SourceType"/> to incorporate advertisements into your application.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="AdRequest" /> object with the Ad options.</param>
        /// <returns>An <see cref="AdResponse" /> with the response to your query.</returns>
        public static AdResponse Ad(SearchRequest searchRequest, AdRequest request)
        {
            searchRequest.Sources = new[] {ApiHelper.SourceType.Ad};
            searchRequest.Version = "2.0";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            WebClient wc = new WebClient();
            wc.Headers.Add("user-agent", "BingSharp/1.0 (Windows; en-US;)");
            string response = wc.DownloadString(requestString);
            XElement element = XElement.Parse(response);

            return AdResponse.ParseElement(element);
        }

        /// <summary>
        /// The Image <see cref="ApiHelper.SourceType"/> returns a list of images relevant to the query term. Image results contain properties about the image media file such as width, height, and file size, along with the URL for the page that contains the image.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="ImageRequest" /> object with the Image options.</param>
        /// <returns>An <see cref="ImageResponse" /> with the response to your query.</returns>
        public static ImageResponse Image(SearchRequest searchRequest, ImageRequest request)
        {

            searchRequest.Sources = new[] { ApiHelper.SourceType.Image };
            searchRequest.Version = "2.0";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return ImageResponse.ParseElement(element);

        }

        /// <summary>
        /// Gets an InstantAnswer from the Bing API.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="InstantAnswerRequest" /> object with the InstantAnswer options.</param>
        /// <returns>An <see cref="InstantAnswerResponse" /> with the response to your query.</returns>
        public static InstantAnswerResponse InstantAnswer(SearchRequest searchRequest, InstantAnswerRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.InstantAnswer };
            searchRequest.Version = "2.0";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return InstantAnswerResponse.ParseElement(element);

        }

        /// <summary>
        /// The MobileWeb <see cref="ApiHelper.SourceType"/> returns mobile Web search results - 
        /// primarily Extensible Hypertext Markup Language (XHTML) or Wireless Markup Language (WML) pages relevant to the queried term. 
        /// MobileWeb results are ordered by an automated ranking algorithm. The Bing ranking algorithm analyzes factors such as page content, 
        /// the number and quality of websites that link to these pages, and the relevance of a website to the query term.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="MobileWebRequest" /> object with the MobileWeb options.</param>
        /// <returns>A <see cref="MobileWebResponse" /> with the response to your query.</returns>
        public static MobileWebResponse MobileWeb(SearchRequest searchRequest, MobileWebRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.MobileWeb };
            searchRequest.Version = "2.1";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return MobileWebResponse.ParseElement(element);
        }

        /// <summary>
        /// News results are presented on the basis of the <see cref="NewsRequest"/> options
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="NewsRequest" /> object with the News options.</param>
        /// <returns>A <see cref="NewsResponse" /> with the response to your query.</returns>
        public static NewsResponse News(SearchRequest searchRequest, NewsRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.News };
            searchRequest.Version = "2.0";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return NewsResponse.ParseElement(element);
        }

        /// <summary>
        /// Uses the Bing API to search for phone numbers
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="PhonebookRequest" /> object with the Phonebook options.</param>
        /// <returns>A <see cref="PhonebookResponse" /> with the response to your query.</returns>
        public static PhonebookResponse Phonebook(SearchRequest searchRequest, PhonebookRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.Phonebook };
            searchRequest.Version = "2.0";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return PhonebookResponse.ParseElement(element);
        }

        /// <summary>
        /// Relateds the search.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="RelatedSearchRequest" /> object with the RelatedSearch options.</param>
        /// <returns>A <see cref="RelatedSearchResponse" /> with the response to your query.</returns>
        public static RelatedSearchResponse RelatedSearch(SearchRequest searchRequest, RelatedSearchRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.RelatedSearch };
            searchRequest.Version = "2.0";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return RelatedSearchResponse.ParseElement(element);

        }

        /// <summary>
        /// Checks the spelling of a word.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="SpellRequest" /> object with the Spell options.</param>
        /// <returns>A <see cref="SpellResponse" /> with the response to your query.</returns>
        /// <remarks>
        /// When a query is sent to the <b>Spell</b> <see cref="ApiHelper.SourceType"/>, alternative spellings for the query based on a number of criteria are proposed. The original query and the alternatives are scored and, if the highest-scoring alternative scores higher than the original, it is returned as a suggested alternative.
        /// </remarks>
        public static SpellResponse Spell(SearchRequest searchRequest, SpellRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.Spell };
            searchRequest.Version = "2.0";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return SpellResponse.ParseElement(element);
        }

        /// <summary>
        /// Translations the query text from the language specified into the destination language.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="TranslationRequest" /> object with the Translation options.</param>
        /// <returns>A <see cref="TranslationResponse" /> with the response to your query.</returns>
        public static TranslationResponse Translation(SearchRequest searchRequest, TranslationRequest request)
        {
            searchRequest.Sources = new[] {ApiHelper.SourceType.Translation};
            searchRequest.Version = "2.2";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();
            
            XElement element = XElement.Load(requestString);

            return TranslationResponse.ParseElement(element);
        }

        /// <summary>
        /// Searches for videos that meet the query.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="VideoRequest" /> object with the Video options.</param>
        /// <returns>A <see cref="VideoResponse" /> with the response to your query.</returns>
        public static VideoResponse Video(SearchRequest searchRequest, VideoRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.Video };
            searchRequest.Version = "2.1";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return VideoResponse.ParseElement(element);
        }

        /// <summary>
        /// Searches for Websites that meet the query.
        /// </summary>
        /// <param name="searchRequest">A <see cref="SearchRequest"/> object with the search options.</param>
        /// <param name="request">The <see cref="WebRequest" /> object with the Web options.</param>
        /// <returns>A <see cref="WebResponse" /> with the response to your query.</returns>
        public static WebResponse Web(SearchRequest searchRequest, WebRequest request)
        {
            searchRequest.Sources = new[] { ApiHelper.SourceType.Web };
            searchRequest.Version = "2.1";
            string requestString = searchRequest.ToQueryString() + request.ToQueryString();

            XElement element = XElement.Load(requestString);

            return WebResponse.ParseElement(element);
        }

        /// <summary>
        /// Multiples the specified search request.
        /// </summary>
        /// <param name="searchRequest">The search request.</param>
        /// <param name="requests">The requests.</param>
        /// <returns>
        /// A <see cref="MultipleSourceResponse"/> with the response to your query.
        /// </returns>
        public static MultipleSourceResponse Multiple(SearchRequest searchRequest, params IBingRequest[] requests)
        {
            searchRequest.Version = "2.1";
            string requestString = searchRequest.ToQueryString();

            foreach (IBingRequest request in requests)
            {
                requestString += request.ToQueryString();
            }

            XElement element = XElement.Load(requestString);

            return MultipleSourceResponse.ParseElement(element);
        }
    }
}
